package com.xh.hongrpc.proxy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.xh.hongrpc.RpcApplication;
import com.xh.hongrpc.config.RpcConfig;
import com.xh.hongrpc.constant.RpcConstant;
import com.xh.hongrpc.fault.retry.RetryStrategy;
import com.xh.hongrpc.fault.retry.RetryStrategyFactory;
import com.xh.hongrpc.fault.tolerant.TolerantStrategy;
import com.xh.hongrpc.fault.tolerant.TolerantStrategyFactory;
import com.xh.hongrpc.loadbalancer.LoadBalancer;
import com.xh.hongrpc.loadbalancer.LoadBalancerFactory;
import com.xh.hongrpc.model.RpcRequest;
import com.xh.hongrpc.model.RpcResponse;
import com.xh.hongrpc.model.ServiceMetaInfo;
import com.xh.hongrpc.protocol.*;
import com.xh.hongrpc.registry.Registry;
import com.xh.hongrpc.registry.RegistryFactory;
import com.xh.hongrpc.serializer.Serializer;
import com.xh.hongrpc.serializer.SerializerFactory;
import com.xh.hongrpc.server.tcp.VertxTcpClient;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 服务代理（JDK 动态代理）
 */
public class ServiceProxy implements InvocationHandler {

    /**
     * 调用代理
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 指定序列化器
//        Serializer serializer = new JdkSerializer();
        // 指定序列化器
        final Serializer serializer = SerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());
        final LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(RpcApplication.getRpcConfig().getLoadBalancer());

        // 构造请求
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();
        // 序列化
//            byte[] bodyBytes = serializer.serialize(rpcRequest);

        try{
            // 从注册中心获取服务提供者请求地址
            RpcConfig rpcConfig = RpcApplication.getRpcConfig();
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(method.getDeclaringClass().getName());
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
            List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfoList)) {
                throw new RuntimeException("暂无服务地址");
            }
            // 暂时先取第一个
            //ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfoList.get(0);

            //均衡负载器选择
            Map<String, Object> requestParams = new HashMap<>();
            requestParams.put("methodName", method.getName());
            ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);
//            // 发送http请求
//            try (HttpResponse httpResponse = HttpRequest.post(selectedServiceMetaInfo.getServiceAddress())
//                    .body(bodyBytes)
//                    .execute()) {
//                byte[] result = httpResponse.bodyBytes();
//                // 反序列化
//                RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
//                reWturn rpcResponse.getData();

            //发送TCP请求
//            RpcResponse  rpcResponse = VertxTcpClient.doRequest(rpcRequest,  selectedServiceMetaInfo);
           RpcResponse rpcResponse;
           try {
               // 使用重试机制
               RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
               rpcResponse = retryStrategy.doRetry(() ->
                       VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo)
               );
           }catch (Exception e){
               //容错机制
               TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
               Map<String, Object> context = new HashMap<>();
               context.put("serviceMetaInfo", selectedServiceMetaInfo);
               context.put("rpcRequest",rpcRequest);
               context.put("selectedServiceMetaInfo",selectedServiceMetaInfo);
               rpcResponse = tolerantStrategy.doTolerant(context, e);
           }
            return rpcResponse.getData();
        } catch (Exception e) {
            throw new RuntimeException("调用失败");
        }
    }
}
